{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8c010ec3",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents import create_structured_chat_agent, AgentExecutor\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.tools import BaseTool, Tool\n",
    "from langchain_experimental.agents.agent_toolkits import create_csv_agent, create_python_agent\n",
    "from langchain_experimental.tools import PythonREPLTool\n",
    "from langchain_openai import ChatOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "b20a5687",
   "metadata": {},
   "outputs": [],
   "source": [
    "model = ChatOpenAI(model='gpt-3.5-turbo')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5cd7c32d",
   "metadata": {},
   "outputs": [],
   "source": [
    "class TextLengthTool(BaseTool):\n",
    "    name = \"文本字数计算工具\"\n",
    "    description = \"当你需要计算文本包含的字数时，使用此工具\"\n",
    "\n",
    "    def _run(self, text):\n",
    "        return len(text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "22112b61",
   "metadata": {},
   "outputs": [],
   "source": [
    "python_agent_executor = create_python_agent(\n",
    "    llm=ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0),\n",
    "    tool=PythonREPLTool(),\n",
    "    verbose=True,\n",
    "    agent_executor_kwargs={\"handle_parsing_errors\": True}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "899d9388",
   "metadata": {},
   "outputs": [],
   "source": [
    "csv_agent_executor = create_csv_agent(\n",
    "    llm=ChatOpenAI(model=\"gpt-3.5-turbo\", temperature=0,),\n",
    "    path=\"house_price.csv\",\n",
    "    verbose=True,\n",
    "    agent_executor_kwargs={\"handle_parsing_errors\": True}\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "04e58a5b",
   "metadata": {},
   "outputs": [],
   "source": [
    "tools=[\n",
    "    Tool(\n",
    "        name=\"Python代码工具\",\n",
    "        description=\"\"\"当你需要借助Python解释器时，使用这个工具。\n",
    "        用自然语言把要求给这个工具，它会生成Python代码并返回代码执行的结果。\"\"\",\n",
    "        func=python_agent_executor.invoke\n",
    "    ),\n",
    "    Tool(\n",
    "        name=\"CSV分析工具\",\n",
    "        description=\"\"\"当你需要回答有关house_price.csv文件的问题时，使用这个工具。\n",
    "        它接受完整的问题作为输入，在使用Pandas库计算后，返回答案。\"\"\",\n",
    "        func=csv_agent_executor.invoke\n",
    "    ),\n",
    "    TextLengthTool()\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c86789a9",
   "metadata": {},
   "outputs": [],
   "source": [
    "memory = ConversationBufferMemory(\n",
    "    memory_key='chat_history',\n",
    "    return_messages=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f6cf78d4-beff-4306-9115-b1814ed851f4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatPromptTemplate(input_variables=['agent_scratchpad', 'input', 'tool_names', 'tools'], input_types={'chat_history': typing.List[typing.Union[langchain_core.messages.ai.AIMessage, langchain_core.messages.human.HumanMessage, langchain_core.messages.chat.ChatMessage, langchain_core.messages.system.SystemMessage, langchain_core.messages.function.FunctionMessage, langchain_core.messages.tool.ToolMessage]]}, metadata={'lc_hub_owner': 'hwchase17', 'lc_hub_repo': 'structured-chat-agent', 'lc_hub_commit_hash': 'ea510f70a5872eb0f41a4e3b7bb004d5711dc127adee08329c664c6c8be5f13c'}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=['tool_names', 'tools'], template='Respond to the human as helpfully and accurately as possible. You have access to the following tools:\\n\\n{tools}\\n\\nUse a json blob to specify a tool by providing an action key (tool name) and an action_input key (tool input).\\n\\nValid \"action\" values: \"Final Answer\" or {tool_names}\\n\\nProvide only ONE action per $JSON_BLOB, as shown:\\n\\n```\\n{{\\n  \"action\": $TOOL_NAME,\\n  \"action_input\": $INPUT\\n}}\\n```\\n\\nFollow this format:\\n\\nQuestion: input question to answer\\nThought: consider previous and subsequent steps\\nAction:\\n```\\n$JSON_BLOB\\n```\\nObservation: action result\\n... (repeat Thought/Action/Observation N times)\\nThought: I know what to respond\\nAction:\\n```\\n{{\\n  \"action\": \"Final Answer\",\\n  \"action_input\": \"Final response to human\"\\n}}\\n\\nBegin! Reminder to ALWAYS respond with a valid json blob of a single action. Use tools if necessary. Respond directly if appropriate. Format is Action:```$JSON_BLOB```then Observation')), MessagesPlaceholder(variable_name='chat_history', optional=True), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['agent_scratchpad', 'input'], template='{input}\\n\\n{agent_scratchpad}\\n (reminder to respond in a JSON blob no matter what)'))])"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prompt = hub.pull(\"hwchase17/structured-chat-agent\")\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "55417ceb-27fc-4e9f-9414-1b3f97987b44",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = create_structured_chat_agent(\n",
    "    llm=model,\n",
    "    tools=tools,\n",
    "    prompt=prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2ae9145a-6800-466b-a963-2ceb3db1aac1",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = AgentExecutor.from_agent_and_tools(\n",
    "    agent=agent, \n",
    "    tools=tools, \n",
    "    memory=memory, \n",
    "    verbose=True, \n",
    "    handle_parsing_errors=True\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "5ad4338a-4d67-4f22-822f-4f3fa8de47dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"Python代码工具\",\n",
      "  \"action_input\": \"fib = lambda n: n if n <= 1 else fib(n-1) + fib(n-2); fib(8)\"\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Python REPL can execute arbitrary code. Use with caution.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[32;1m\u001b[1;3mWe are given a lambda function that calculates the Fibonacci sequence recursively. We need to find the 8th Fibonacci number.\n",
      "Action: Python_REPL\n",
      "Action Input: fib = lambda n: n if n <= 1 else fib(n-1) + fib(n-2); fib(8)\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3mThe code is executing the lambda function to find the 8th Fibonacci number.\n",
      "Final Answer: 21\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[36;1m\u001b[1;3m{'input': 'fib = lambda n: n if n <= 1 else fib(n-1) + fib(n-2); fib(8)', 'output': '21'}\u001b[0m\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"Final Answer\",\n",
      "  \"action_input\": 21\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': '第8个斐波那契数列的数字是多少？',\n",
       " 'chat_history': [HumanMessage(content='第8个斐波那契数列的数字是多少？'),\n",
       "  AIMessage(content='21')],\n",
       " 'output': 21}"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"第8个斐波那契数列的数字是多少？\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "580aa3de",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"CSV分析工具\",\n",
      "  \"action_input\": \"What is the average price of all houses in the dataset?\"\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mThought: To find the average price, we need to calculate the mean of the 'price' column in the dataframe.\n",
      "Action: python_repl_ast\n",
      "Action Input: df['price'].mean()\u001b[0m\u001b[36;1m\u001b[1;3m4766729.247706422\u001b[0m\u001b[32;1m\u001b[1;3mI now know the final answer\n",
      "Final Answer: The average price of all houses in the dataset is $4,766,729.25.\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n",
      "\u001b[33;1m\u001b[1;3m{'input': 'What is the average price of all houses in the dataset?', 'output': 'The average price of all houses in the dataset is $4,766,729.25.'}\u001b[0m\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"Final Answer\",\n",
      "  \"action_input\": \"数据集中所有房屋的平均价格是4766729.25\"\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': 'house_price数据集里，所有房子的价格平均值是多少？用中文回答',\n",
       " 'chat_history': [HumanMessage(content='第8个斐波那契数列的数字是多少？'),\n",
       "  AIMessage(content='21'),\n",
       "  HumanMessage(content='house_price数据集里，所有房子的价格平均值是多少？用中文回答'),\n",
       "  AIMessage(content='数据集中所有房屋的平均价格是4766729.25')],\n",
       " 'output': '数据集中所有房屋的平均价格是4766729.25'}"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"house_price数据集里，所有房子的价格平均值是多少？用中文回答\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "e02b10e5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"文本字数计算工具\",\n",
      "  \"action_input\": {\n",
      "    \"text\": \"君不见黄河之水天上来奔流到海不复回\"\n",
      "  }\n",
      "}\u001b[0m\u001b[38;5;200m\u001b[1;3m17\u001b[0m\u001b[32;1m\u001b[1;3m{\n",
      "  \"action\": \"Final Answer\",\n",
      "  \"action_input\": \"17\"\n",
      "}\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'input': \"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\",\n",
       " 'chat_history': [HumanMessage(content='第8个斐波那契数列的数字是多少？'),\n",
       "  AIMessage(content='21'),\n",
       "  HumanMessage(content='house_price数据集里，所有房子的价格平均值是多少？用中文回答'),\n",
       "  AIMessage(content='数据集中所有房屋的平均价格是4766729.25'),\n",
       "  HumanMessage(content=\"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\"),\n",
       "  AIMessage(content='17')],\n",
       " 'output': '17'}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"'君不见黄河之水天上来奔流到海不复回'，这句话的字数是多少？\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
